﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Schema;
using SellAvi.Model.AvitoSocketModels;
using SellAvi.Schemas.JsonSchemas;
using SuperSocket.ClientEngine;
using WebSocket4Net;

namespace SellAvi.ViewModel
{
    partial class MailingViewModel
    {
        private WebSocket _websocket;
        private HashSet<string> _chatroomsIds = new HashSet<string>(); 
        private const string SocketServer = "wss://socket2.avito.ru";
        public ObservableCollection<channel> ChatSessionsCollection { get; set; }
        public result_chat ChatInfo { get; set; }
        public string MessageText { get; set; }


        private int _socketPacketIn;
        public int SocketPacketIn
        {
            get { return _socketPacketIn; }
            set
            {
                _socketPacketIn = value;
                RaisePropertyChanged("SocketPacketIn");
            }
        }
        private int _socketPacketOut;
        public int SocketPacketOut
        {
            get { return _socketPacketOut; }
            set
            {
                _socketPacketOut = value;
                RaisePropertyChanged("SocketPacketOut");
            }
        }

        private int _chatUserId;
        public int ChatUserId
        {
            get { return _chatUserId; }
            set
            {
                _chatUserId = value;
                RaisePropertyChanged("ChatUserId");
            }
        }


        private string _socketLogging;
        public string SocketLogging
        {
            get { return _socketLogging; }
            set
            {
                _socketLogging = value;
                RaisePropertyChanged("SocketLogging");
            }
        }

        public string SocketState
        {
            get
            {
                if (_websocket != null)
                {
                    return _websocket.State.ToString();

                }
                return null;
            }
        }

        private bool _autoReplyState;
        public bool AutoReplyState
        {
            get { return _autoReplyState; }
            set
            {
                _autoReplyState = value;
                RaisePropertyChanged("AutoReplyState");
            }
        }

        private int _incomingMessages;
        public int IncomingMessages
        {
            get { return _incomingMessages; }
            set
            {
                _incomingMessages = value;
                RaisePropertyChanged("IncomingMessages");
            }
        }
        private int _outcomingMessages;
        public int OutcomingMessages
        {
            get { return _outcomingMessages; }
            set
            {
                _outcomingMessages = value;
                RaisePropertyChanged("OutcomingMessages");
            }
        }
        private message _lastMessage;
        public message LastMessage
        {
            get { return _lastMessage; }
            set
            {
                _lastMessage = value;
                RaisePropertyChanged("LastMessage");
            }
        }

        private void SocketOpen()
        {
            if (Webclient != null)
            {
                if (SocketState == null || _websocket.State == WebSocketState.Closed)
                {
                    _websocket = new WebSocket(SocketServer, null, PrepareWebsocketCookies(),
                        PrepareCustomHeaders(), Webclient.DefaultHeaders[HttpRequestHeader.UserAgent], "https://www.avito.ru",
                        WebSocketVersion.Rfc6455) { AllowUnstrustedCertificate = true };

                    _websocket.Opened += new EventHandler(websocket_Opened);
                    _websocket.Error += new EventHandler<ErrorEventArgs>(websocket_Error);
                    _websocket.Closed += new EventHandler(websocket_Closed);
                    _websocket.MessageReceived += new EventHandler<MessageReceivedEventArgs>(websocket_MessageReceived);
                    _websocket.EnableAutoSendPing = true;
                    _websocket.Open();
                    AutoReplyState = true;
                }
                else
                {
                    _websocket.Close();
                }

            }
            else
            {
                MessageBox.Show("Для выполнения операции необходима авторизация в программе!", "Требуется авторизация",
                    MessageBoxButton.OK, MessageBoxImage.Asterisk);
            }
        }

        private void ReloadChatInfo()
        {
            if (_websocket != null)
            {
                SocketPacketOut += 2;
                //запрос для получени информации по товару включая UserId пользователя
                //var message = @"{""id"":" + SocketPacketOut + @",""method"":""avito.getBodyItems"",""params"":{""ids"":[897537011]},""jsonrpc"":""2.0""}";
                var message = @"{""id"":" + SocketPacketOut + @",""method"":""avito.getChats"",""params"":{""offset"":0,""limit"":100,""filters"":{}},""jsonrpc"":""2.0""}";
                _websocket.Send(message);
            }
        }

        private void websocket_Error(object sender, ErrorEventArgs errorEventArgs)
        {
            Console.WriteLine(errorEventArgs.Exception);
            RaisePropertyChanged("SocketState");
        }

        private void websocket_MessageReceived(object sender, EventArgs eventArgs)
        {
            var socketResponse = ((MessageReceivedEventArgs)(eventArgs)).Message;
            SocketLogging = socketResponse;
            JObject message = JObject.Parse(socketResponse);

            // Идентификатор сообщения
            if (message.Property("id") != null)
            {
                SocketPacketIn = message.Property("id").First.Value<int>();
            }
            // Идентификатор пользователя
            if (message.SelectToken("$.value.userId") != null)
            {
                ChatUserId = (int)message.SelectToken("$.value.userId");
            }
            // Подгрузка последних сообщений
            if (message.IsValid(JsonSchema.Parse(Encoding.UTF8.GetString(SchemaResources.channel))))
            {
                var s = JsonConvert.DeserializeObject<response_result_channel>(socketResponse, new JsonSerializerSettings() { Error = DeserializationErrorHandling });
                ChatSessionsCollection = new ObservableCollection<channel>(s.result.channels);
                RaisePropertyChanged("ChatSessionsCollection");

            }
            // Прочитанных сообщений
            if (message.IsValid(JsonSchema.Parse(Encoding.UTF8.GetString(SchemaResources.chat))))
            {
                var s = JsonConvert.DeserializeObject<response_result_chat>(socketResponse, new JsonSerializerSettings() { Error = DeserializationErrorHandling });
                ChatInfo = s.result;
                RaisePropertyChanged("ChatInfo");
            }
            // Входящие сообщение
            if (message.IsValid(JsonSchema.Parse(Encoding.UTF8.GetString(SchemaResources.message))))
            {
                var s = JsonConvert.DeserializeObject<response_value_message>(socketResponse, new JsonSerializerSettings() { Error = DeserializationErrorHandling });
                IncomingMessages++;
                LastMessage = s.value.data;
                //_chatroomsIds.Add(s.value.data.channelId);
                if (AutoReplyState == true && !_chatroomsIds.Contains(s.value.data.channelId) && LastMessage.fromUid != ChatUserId)
                {
                    _chatroomsIds.Add(s.value.data.channelId);
                    SendSocketAutoReply(s.value.data.channelId);
                }

            }



        }

        private void DeserializationErrorHandling(object sender, Newtonsoft.Json.Serialization.ErrorEventArgs errorEventArgs)
        {
            Logger.Error("Ошибка обработки Json: {0}", errorEventArgs.ErrorContext.Error.Message);
            errorEventArgs.ErrorContext.Handled = true;
        }

        private void websocket_Closed(object sender, EventArgs eventArgs)
        {
            SocketLogging = "Соединение с avito закрыто.";
            RaisePropertyChanged("SocketState");

        }

        private void websocket_Opened(object sender, EventArgs eventArgs)
        {
            SocketLogging = "Соединение открыто.";
            RaisePropertyChanged("SocketState");

            _websocket.Send(@"{""id"":1,""method"":""acks"",""params"":{""ids"":[2]},""jsonrpc"":""2.0""}");
            _websocket.Send(@"{""id"":3,""method"":""avito.getChatCounters"",""params"":{},""jsonrpc"":""2.0""}");
            _websocket.Send(@"{""id"":5,""method"":""avito.getChats"",""params"":{""offset"":0,""limit"":100,""filters"":{}},""jsonrpc"":""2.0""}");

            SocketPacketOut = 5; //offset

            var _cancellationToken = new CancellationTokenSource();
            Task.Factory.StartNew(_ => SendSocketAutoPing(), _cancellationToken.Token)
                .ContinueWith(_ => { });
        }

        private List<KeyValuePair<string, string>> PrepareWebsocketCookies()
        {
            var container = new List<KeyValuePair<string, string>>();
            var cookieString = Webclient.CookieContainer.GetCookieHeader(new Uri("https://www.avito.ru"));
            //var cookie = "u=21xfv06a.ctcggq.f88c91n7sl; _ym_uid=1474973500233043501; __gads=ID=04591024fc728a3c:T=1474973499:S=ALNI_MY_VrTcBj5tzLvk6Spe5nUKqBTjaA; vishnu1.new_chat=1; vishnu1.cuid=bafbda33-f7ed-42b9-a733-ae2cf65560d7; vishnu1.visible=0; _jsuid=4126337624; dfp_group=76; reklama-no-request=1; f=4.b53ee41b77d9840ae5ba07059b0d202f6e619f2005f5c6dc6e619f2005f5c6dc6e619f2005f5c6dc6e619f2005f5c6dc6e619f2005f5c6dc6e619f2005f5c6dc6e619f2005f5c6dc6e619f2005f5c6dc6e619f2005f5c6dc6e619f2005f5c6dc5b68b402642848be5b68b402642848bead33eaef55dd0da1f7d75d53b929b44c44620aa09dfab02de75a2b007093b89d05886bb864a616652f4891ba472e4f2618dc79c78ea31ba1ea48e2d99c5312aaffe65fd77b784b7bffe65fd77b784b7bb8a109ce707ef6137c6d6c44a42cb1c70176a16018517b5da399e993193588ae728b89f8cc435269728b89f8cc435269728b89f8cc435269728b89f8cc435269ffe65fd77b784b7b862357a052e106f23f601feec47f73646b10d486f2e98b94ca112ee97349d08fcd1583c110bfb60eb5625d268f549a9fb1bb2a353daea3d2983634ac97fc2097e59bc492ed15ed1b9421779967acfec4d9fcb3420731623d7c6d6c44a42cb1c77c6d6c44a42cb1c7ea48e2d99c5312aa9f8aee6ba1bc3a09; _ym_isad=1; nfh=12d0aa5dfd78cb805725fedb5f7846a3; _ga=GA1.2.150182955.1474973500; sessid=9389f1e1a56fed49d933ff6b6f791491.1490605768; crtg_rta=cravadb240%3D1%3B; _ym_visorc_34241905=b; __utmt=1; auth=1; anid=899063286%3Bb0be8baa939e3b5d531107058fdf7046%3B1; weborama-viewed=1; __utma=99926606.150182955.1474973500.1490698664.1490705486.154; __utmb=99926606.3.10.1490705488; __utmc=99926606; __utmz=99926606.1490698664.153.27.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided); v=1490705485";

            //container.Add(new KeyValuePair<string, string>("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36"));
            //container.Add(new KeyValuePair<string, string>("Host", "socket2.avito.ru"));

            foreach (var cookieElement in cookieString.Split(';'))
            {
                var key = cookieElement.Split('=')[0].Trim();
                var value = cookieElement.Split('=')[1].Trim();
                container.Add(new KeyValuePair<string, string>(key, value));
            }
            return container;
        }

        private List<KeyValuePair<string, string>> PrepareCustomHeaders()
        {
            var container = new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string, string>("Sec-WebSocket-Key", Convert.ToBase64String(Encoding.UTF8.GetBytes(new Guid().ToString()))),//F04XHTP6yBzbWQjUKej9tQ==
                new KeyValuePair<string, string>("Sec-WebSocket-Extensions","permessage-deflate; client_max_window_bits"),
                new KeyValuePair<string, string>("Upgrade", "_websocket")
            };

            return container;

        }



        private void SendSocketAutoPing()
        {
            while (_websocket.State == WebSocketState.Open)
            {
                SocketPacketOut += 2;
                Task.Delay(TimeSpan.FromMilliseconds(10000), /*_cancellationToken.Token*/ new CancellationToken()).Wait();
                var pingMessage = @"{""id"":" + SocketPacketOut + @",""method"":""ping"",""params"":{},""jsonrpc"":""2.0""}"; ;
                _websocket.Send(pingMessage);
            }
        }

        private void SendSocketAutoReply(string channelId)
        {
            SocketPacketOut += 2;
            OutcomingMessages ++;
            var pingMessage =   @"{""id"":"
                                + SocketPacketOut
                                + @",""method"":""avito.sendTextMessage"",""params"":{""channelId"":"""
                                + channelId 
                                + @""",""text"":"""
                                + MessageText
                                + @"""},""jsonrpc"":""2.0""}";
            _websocket.Send(pingMessage);

        }
    }
}
